<?php
/**
 * PeriodeTable.php
 */

namespace RHX\Model\Table;

use Zend\Db\Adapter\Adapter;
use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\ResultSet\ResultSet;
use RHX\Model\Object\Periode;
use Zend\Db\Sql\Select;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Expression;

class PeriodeTable extends AbstractTableGateway {

    /**
     * Nom de la table dans la base de données
     *
     * @var string $table
     */
    protected $table = 'rh_periode';

    /**
     * Constructeur de la Classe
     * 
     * @param \RHX\Model\Table\Adapter $adapter
     */
    public function __construct(Adapter $adapter) {
	$this->adapter			 = $adapter;
	$this->resultSetPrototype	 = new ResultSet();
	$this->resultSetPrototype->setArrayObjectPrototype(new Periode());
	$this->initialize();
    }

    /**
     * Tous les Périodes de la table
     *
     * @param string $order Ordre d'affichage
     * @return type
     */
    public function getAll($order = 'id ASC') {
	return $this->select(function(Select $select) use($order) {
			    $select->order($order);
			});
    }

    /**
     * Afficher les Périodes par page
     * 
     * @param string $order Ordre d'affichage
     * @param type $page Numéro de page
     * @param type $perPage Objet par page
     * @return type
     */
    public function getPeriodes($order = 'id ASC', $page = 1, $perPage = 15) {
	return $this->select(function(Select $select) use($order, $page, $perPage) {
			    $select->order($order);
			    $offset = ($page - 1) * $perPage;
			    $select->offset($offset);
			    $select->limit($perPage);
			});
    }

    /**
     * Récupérer une/plusieurs périodes à partir d'une date
     *
     * @param string $date
     * @param bool $all
     * @return array
     */
    public function getPeriodeByDate($date = null, $all = false) {
	if (is_null($date)) {
	    $date = date('Y-m-d');
	}
	$date		 = new \RHX\Helper\RHDateTime($date);
	// SELECT * FROM rh_periode WHERE '2013-08-27' BETWEEN debut AND fin
	$sql		 = "SELECT * FROM " . $this->table . " WHERE '" . $date->date('Y-m-d') . "' BETWEEN debut AND fin";
	$result		 = $this->adapter
		->query($sql)
		->execute();
	$periodes	 = array();
	foreach ($result as $row) {
	    $periodes[] = $row;
	}
//	\Zend\Debug\Debug::dump($periodes, 'Période');
//	\Zend\Debug\Debug::dump($sql, 'Requête SQL');
	if (!$all) {
	    return isset($periodes[0]) ? $periodes[0] : null;
	}
	else {
	    return $periodes;
	}
    }
    

    /**
     * Récupérer une Période
     * 
     * @param int $id
     * @return Periode
     * @throws \Exception
     */
    public function get($id) {
	$row = $this->select(array('id' => $id))
		->current();
	if (!$row)
	    throw new \Exception("Erreur #11 : La Période #$id est introuvable");

	return $row;
    }

    /**
     * Sauvegarder une Période
     * 
     * @param \RHX\Model\Object\Periode $periode
     * @return int L'identifiant du Dernier enregistrement ou Le nouveau pour l'insertion
     * @throws \Exception
     */
    public function save(Periode $periode) {
	$data	 = array(
	    'libelle'	 => $periode->libelle,
	    'debut'		 => $periode->debut,
	    'fin'		 => $periode->fin,
	);
	$id	 = (int) $periode->id;
	if ($id == 0) {
	    // Insertion
	    $this->insert($data);
	}
	elseif ($this->get($id)) {
	    // Mise à jour
	    $this->update($data, array('id' => $id));
	}
	else {
	    throw new \Exception("Erreur #12 : La Période #$id n'a pas été sélectionnée");
	}
	if ($id == 0)
	    return $this->lastInsertValue;
	else
	    return $id;
    }

    /**
     * Effacer un Enregistrement
     * 
     * @param type $id
     * @return int Le nombre de lignes affectées
     */
    public function erase($id) {
	return $this->delete(array('id' => $id));
    }

    /**
     * Tableau des Périodes pour une utilisation dans une Zone de liste
     * 
     * @return array
     */
    public function getSelectList() {
	$rows	 = $this->select();
	$ret	 = array();
	foreach ($rows as $p) {
	    $ret[$p->id] = html_entity_decode($p->libelle);
	}

	return $ret;
    }

    /**
     * Récupérer la valeur Maximale des Identifiants
     * 
     * @return int
     */
    public function getMaxValue() {
	$sql		 = new Sql($this->adapter);
	$select		 = $sql->select();
	$select->from($this->table);
	$select->columns(array(
	    'max' => new Expression("MAX(id)"),
	));
	$statement	 = $sql->prepareStatementForSqlObject($select);
	$result		 = $statement->execute()->current();

	return (int) $result['max'];
    }

    /**
     * Récupérer la Prochaine Valeur de l'Identifiant
     * 
     * @return int
     */
    public function getNextValue() {
	$max = $this->getMaxValue();
	$max++;

	return $max;
    }

    /**
     * Récupérer le Prochain Lundi
     * 
     * @return \RHX\Helper\RHDateTime
     */
    public function getNextMonday() {
	$sql		 = new Sql($this->adapter);
	$select		 = $sql->select();
	$select->from($this->table);
	// On sélectionne le dernier date dans la période et on ajoute un jour
	// Le Dernier jour doit toujours correspondre à un Dimanche
	$select->columns(array(
	    'next_monday' => new Expression('DATE_ADD(MAX(fin), INTERVAL 1 DAY)'),
	));
	$statement	 = $sql->prepareStatementForSqlObject($select);
	$result		 = $statement->execute();
	$count		 = $result->count();
	//var_dump($count);
	$current	 = $result->current();
	if ($count < 1 || $current['next_monday'] == '' || is_null($current['next_monday'])) {
	    // Il n'ya pas de lundi suivant : La base de données est vide
	    $now = new \RHX\Helper\RHDateTime();
	    if ($now->isDay('lundi')) {
		return $now;
	    }
	    else {
		return new \RHX\Helper\RHDateTime('next monday');
	    }
	}
	else {
	    // Il y a au moins un résultat
	    return new \RHX\Helper\RHDateTime($current['next_monday']);
	}
    }

    /**
     * Récupérer le Prochain libellé
     * 
     * @return string
     */
    public function getNextLabel() {
	return 'Periode ' . $this->getNextValue();
    }

    /**
     * Récupérer les 5 Dimanches suivants
     * 
     * @return \RHX\Helper\RHDateTime
     */
    public function getNextSundays() {
	$sql	 = new Sql($this->adapter);
	$select	 = $sql->select();
	$select->from(array('p' => $this->table));
	$select->columns(array(
	    'sunday_1'	 => new Expression("DATE_ADD(MAX(fin), INTERVAL 7 DAY)"),
	    'sunday_2'	 => new Expression("DATE_ADD(MAX(fin), INTERVAL 14 DAY)"),
	    'sunday_3'	 => new Expression("DATE_ADD(MAX(fin), INTERVAL 21 DAY)"),
	    'sunday_4'	 => new Expression("DATE_ADD(MAX(fin), INTERVAL 28 DAY)"),
	    'sunday_5'	 => new Expression("DATE_ADD(MAX(fin), INTERVAL 35 DAY)"),
	));
	$state	 = $sql->prepareStatementForSqlObject($select);
	$result	 = $state->execute();
	$current = $result->current();
	$sundays = array();
	if (is_null($current['sunday_1'])) {
	    // Il n'y a pas d'enregistrement dans la base
	    // On crée des date
	    $sunday1		 = new \RHX\Helper\RHDateTime('next sunday');
	    $sundays['sunday1']	 = $sunday1;
	    $sunday2		 = new \RHX\Helper\RHDateTime('next sunday');
	    $sunday2->modify('next sunday');
	    $sundays['sunday2']	 = $sunday2;
	    $sunday3		 = new \RHX\Helper\RHDateTime('next sunday');
	    $sunday3->modify('next sunday');
	    $sunday3->modify('next sunday');
	    $sundays['sunday3']	 = $sunday3;
	    $sunday4		 = new \RHX\Helper\RHDateTime('next sunday');
	    $sunday4->modify('next sunday');
	    $sunday4->modify('next sunday');
	    $sunday4->modify('next sunday');
	    $sundays['sunday4']	 = $sunday4;
	    $sunday5		 = new \RHX\Helper\RHDateTime('next sunday');
	    $sunday5->modify('next sunday');
	    $sunday5->modify('next sunday');
	    $sunday5->modify('next sunday');
	    $sunday5->modify('next sunday');
	    $sundays['sunday5']	 = $sunday5;
	}
	else {
	    // Il y a des enregistrement
	    $sundays['sunday1']	 = new \RHX\Helper\RHDateTime($current['sunday_1']);
	    $sundays['sunday2']	 = new \RHX\Helper\RHDateTime($current['sunday_2']);
	    $sundays['sunday3']	 = new \RHX\Helper\RHDateTime($current['sunday_3']);
	    $sundays['sunday4']	 = new \RHX\Helper\RHDateTime($current['sunday_4']);
	    $sundays['sunday5']	 = new \RHX\Helper\RHDateTime($current['sunday_5']);
	}

	return $sundays;
    }

    /**
     * Période correspondant à la date donnée
     * 
     * @param string $date
     * @return \RHX\Model\Object\Periode
     */
    public function getPeriode($date) {
	$sql	 = "SELECT * FROM rh_periode WHERE '$date' BETWEEN debut AND fin";
	$result	 = $this->adapter
		->query($sql)
		->execute();
	$current = array();
	foreach ($result as $r) {
	    $current = $r;
	    break;
	}
	$periode = new Periode($current);

	return $periode;
    }
    
    /**
     * Dernière période
     * 
     * @return Periode
     */
    public function getLastPeriode(){
	return $this->select(function(Select $select){
	    $where = new \Zend\Db\Sql\Where();
	    $where->literal('MAX(id)');
            $select->where($where);
	})->current();
    }
    
    /* Récupère les Periode future à une date donnée
     * @param string $date date de référence (non comprise dans le calcul)
     * si omis la date du jour sera prise
     * 
     * @return \RHX\Model\Object\Periode
     */
    
    public function getFuturePeriode( $date = null ){
        
        if(!$date){
            $date = date("Y-m-d");
        }
        
        $sql = "SELECT * FROM rh_periode WHERE debut > '$date'";        
        $statement = $this->adapter->query($sql);
        $result =  $statement->execute();
        
        $periodes = array();
        foreach($result as $row):
            $periodes[] = new Periode($row);
        endforeach;
        
        return $periodes;
    }
    
    /**
     * Récupérer les périodes futures
     * 
     * @param \RHX\Model\Object\Periode $periodeEnCours
     * @return ResultSet
     */
    public function getPeriodeFutures(Periode $periodeEnCours){
        $rows = $this->select(function(Select $select)use($periodeEnCours){
            $where = new \Zend\Db\Sql\Where();
            $where->greaterThan('id', $periodeEnCours->id);
            $select->where($where);
        });
        return ($rows->count() > 0) ? $this->transformToArray($rows) : NULL;
    }
    
    /**
     * Transformer en tableau
     * 
     * @param ResultSet $rows
     * @return array
     */
    private function transformToArray($rows){
        if(is_null($rows)) return NULL;
        $array = array();
        foreach($rows as $row){
            $array[] = $row;
        }
        return $array;
    }


    /**
     * Récupération de la dernière période
     * 
     * @return Periode
     */
    public function getTheLastPeriode(){
        $maxId = $this->getMaxValue();
        $row = $this->select(function(Select $select)use($maxId){
            $where = new \Zend\Db\Sql\Where();
            $where->equalTo('id', $maxId);
            $select->where($where);
        })->current();
        return ($row) ? $row : NULL;
    }

}

